package com.xiaoshuidi.cloud.module.contract.controller.admin.bill;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.PdfWriter;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.excel.core.util.ExcelUtils;
import com.xiaoshuidi.cloud.framework.operatelog.core.annotations.OperateLog;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.bpm.api.task.BpmProcessInstanceApi;
import com.xiaoshuidi.cloud.module.bpm.api.task.dto.BpmTaskRespDTO;
import com.xiaoshuidi.cloud.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.ownerOrder.*;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.rentOrder.RentOrderInfoVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.HomeQueryVO;
import com.xiaoshuidi.cloud.module.contract.convert.bill.RentOrderConvert;
import com.xiaoshuidi.cloud.module.contract.convert.contract.ContractHouseOwnerConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OrderFeesDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OwnerOrderTransferDO;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderTypeEnum;
import com.xiaoshuidi.cloud.module.contract.job.OwnerContractJob;
import com.xiaoshuidi.cloud.module.contract.service.bill.OrderFeesService;
import com.xiaoshuidi.cloud.module.contract.service.bill.OwnerOrderService;
import com.xiaoshuidi.cloud.module.contract.service.bill.RentOrderService;
import com.xiaoshuidi.cloud.module.contract.service.home.HomeService;
import com.xiaoshuidi.cloud.module.contract.util.pdf.PdfUtils;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.BankTransferReqDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static com.xiaoshuidi.cloud.framework.common.pojo.CommonResult.success;
import static com.xiaoshuidi.cloud.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;

@Tag(name = "管理后台 - 业主账单")
@RestController
@RequestMapping(ApiConstants.NAME + "/owner-order")
@Validated
public class OwnerOrderController {

    @Resource
    private OwnerOrderService ownerOrderService;
    @Resource
    private RentOrderService rentOrderService;
    @Resource
    private HomeService homeService;
    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Resource
    private OrderFeesService orderFeesService;

    /**
     * 获得业主账单分页
     */
    @GetMapping("/page")
    @Operation(summary = "获得业主账单分页")
//    @PreAuthorize("@ss.hasPermission('contract:owner:query')")
    public CommonResult<PageResult<OwnerOrderRespVO>> getHouseOwnerPage(@Valid OwnerOrderPageReqVO pageReqVO) {
        return success(ownerOrderService.getOwnerOrderPage(pageReqVO));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出业主账单 Excel")
//    @PreAuthorize("@ss.hasPermission('contract:owner:export')")
    @OperateLog(type = EXPORT)
    public void exportOwnerOrderExcel(@Valid OwnerOrderPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        List<OwnerOrderRespVO> list = ownerOrderService.getOwnerOrderList(pageReqVO);
        // 导出 Excel
        List<OwnerOrderExcelVO> datas = RentOrderConvert.INSTANCE.ownerOrderRespVOs2OwnerOrderExcelVOs(list);
        ExcelUtils.write(response, "业主账单.xls", "数据", OwnerOrderExcelVO.class, datas);
    }

    @GetMapping("/get")
    @Operation(summary = "获得业主账单")
    @Parameter(name = "id", description = "合同ID", required = true, example = "1024")
//    @PreAuthorize("@ss.hasPermission('contract:owner:query')")
    public CommonResult<RentOrderInfoVO> getHouseOwner(@RequestParam("id") Long id) {
        return success(rentOrderService.getRentOrder(id, Arrays.asList(OrderTypeEnum.OWNER.getCode())));
    }

    @GetMapping("/get-info")
    @Operation(summary = "获得业主账单基本信息")
    @Parameter(name = "id", description = "账单ID", required = true, example = "1024")
//    @PreAuthorize("@ss.hasPermission('contract:owner:query')")
    public CommonResult<OwnerOrderInfoRespVO> getOwnerOrderInfo(@RequestParam("id") Long id) {
        return success(ownerOrderService.getOwnerOrderInfo(id));
    }

    /**
     * 业主账单交租（付给业主）
     */
    @PostMapping("/pay-rent")
    @Operation(summary = "业主账单交租（付给业主）")
    public CommonResult<Boolean> payRent(@RequestBody BankTransferReqDTO req) {
        req.setOperator(SecurityFrameworkUtils.getLoginUser().getNickname());
        ownerOrderService.payRent(req);
        return success(true);
    }

    /**
     * 获得首页应付账单分页
     */
    @GetMapping("/payable-order-page")
    @Operation(summary = "获得首页应付账单分页")
//    @PreAuthorize("@ss.hasPermission('contract:owner:query')")
    public CommonResult<OwnerOrderHomeDateVO> getHomeHouseOwnerPage(@Valid HomeQueryVO queryDTO) {
        OwnerOrderHomeDateVO result = new OwnerOrderHomeDateVO();
        result.setPageResult(ownerOrderService.getOwnerOrderHomePage(queryDTO));
        result.setHomeData(homeService.getHomeData(queryDTO));
        return success(result);
    }

    /**
     * 业主合同终止付款
     * @return
     */
    @PostMapping("/suspend")
    @Operation(summary = "中止付款")
    public CommonResult<Void> suspend(@Valid @RequestBody OwnerOrderSuspendReqVO reqVO) {
        ownerOrderService.suspend(reqVO);
        return success();
    }

    @GetMapping("/transfer/page")
    @Operation(summary = "委托付款列表")
    public CommonResult<OwnerOrderTransferPageRespVO> transferPage(OwnerOrderTransferPageReqVO reqVO) {
        PageResult<OwnerOrderTransferDO> pageResult = ownerOrderService.getTransferPage(reqVO);
        OwnerOrderTransferPageRespVO result = ownerOrderService.getTransferSummary(reqVO);
        result.setList(pageResult.getList());
        result.setTotal(pageResult.getTotal());
        return success(result);
    }

    @GetMapping("/transfer/get")
    @Operation(summary = "委托付款详情")
    public CommonResult<OwnerOrderTransferRespVO> transferDetail(@RequestParam("id") Long id) {
        OwnerOrderTransferDO o = ownerOrderService.getTransferDetail(id);
        OwnerOrderTransferRespVO respVO = new OwnerOrderTransferRespVO();
        respVO.setDetail(o);
        respVO.setFees(RentOrderConvert.INSTANCE.convert2(orderFeesService.getOrderFeesByOrderId(o.getOrderId())));
        return CommonResult.success(respVO);
    }

    @PostMapping("/transfer/confirm")
    @Operation(summary = "委托付款确认付款")
    public CommonResult<Void> transferConfirm(@RequestBody OwnerOrderTransferReqVO reqVO) {
        ownerOrderService.transfer(reqVO, SecurityFrameworkUtils.getLoginUser().getNickname());
        return success();
    }

    /**
     * 委托业主账单审批详情
     *
     * @param id
     * @return
     */
    @GetMapping("/ownerOrder/get")
    @Operation(summary = "委托业主账单审批详情")
    public CommonResult<OwnerOrderApprovalDetailVO> ownerOrderApprovalDetailById(@RequestParam("id") Long id) {
        return success(ownerOrderService.ownerOrderApprovalDetailById(id));
    }

    /**
     * 业主账单打款发起审批
     *
     * @param id
     * @return
     */
    @PostMapping("/ownerOrder/approval")
    @Operation(summary = "业主账单打款发起审批")
    public CommonResult<Void> ownerOrderCreateApproval(@RequestParam("id") Long id) {
        ownerOrderService.ownerOrderCreateApproval(id);
        return success();
    }

    @GetMapping("/transfer/export")
    @Operation(summary = "委托付款明细导出")
    public void transferExport(OwnerOrderTransferPageReqVO reqVO, HttpServletResponse response) throws IOException {
        reqVO.setPageSize(100);
        PageResult<OwnerOrderTransferDO> pageResult = ownerOrderService.getTransferPage(reqVO);

        ExcelUtils.write(response, "委托付款明细.xlsx", "委托付款明细", OwnerOrderTransferExcelVO.class, pageResult,
                ContractHouseOwnerConvert.INSTANCE::convert, pageNo -> {
                    reqVO.setPageNo(pageNo);
                    return ownerOrderService.getTransferPage(reqVO);
                }
        );
    }

    @GetMapping("/transfer/pdf")
    @Operation(summary = "批量打印委托付款单")
    public void transferPdf(@RequestParam("ids") String ids, HttpServletResponse response) throws IOException, DocumentException {
        List<OwnerOrderTransferDO> list = ownerOrderService.getTransferList(ids.split(","));
        Font header = PdfUtils.getFont();
        header.setSize(18);
        header.setStyle(Font.FontStyle.BOLD.getValue());
        Font bold = PdfUtils.getFont();
        bold.setStyle(Font.FontStyle.BOLD.getValue());

        PdfUtils.PdfDoc doc = PdfUtils.newPdfDoc();
        OutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(String.format("公司经费支出联签单_%s.pdf", DateUtil.format(new Date(), "yyyyMMddHHmmss")), "UTF-8"));
        response.setContentType("application/pdf;charset=UTF-8");

        PdfWriter.getInstance(doc.getDoc(), os);
        doc.open();
        if (CollectionUtils.isEmpty(list)) {
            doc.addParagraph("未找到委托付款信息");
            doc.close();
            os.close();
            return;
        }
        for (OwnerOrderTransferDO vo : list) {
            List<OrderFeesDO> detail = orderFeesService.getOrderFeesByOrderId(vo.getOrderId());

            doc.addParagraph(DateUtil.format(new Date(), "yyyy/MM/dd"));
            doc.addTable(4, tb -> {
                        // 主表单信息
                tb.addCell("公司经费支出联签单", 4, header, cell -> {
                            cell.setPaddingTop(5);
                            cell.setPaddingBottom(10);
                        })
                        .addCell("账单信息", 4, bold, Element.ALIGN_LEFT)
                        .addCell("申请部门").addCell(vo.getApartmentName(), "申请日期",
                                ObjectUtil.isNotEmpty(vo.getConfirmTime()) ?
                                vo.getConfirmTime().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) : "")
                        .addCell("申请人", vo.getOperator(), "单位", "元")
                        .addCell("经费支出事由").addCell("分散式房源" + vo.getApartmentName() + vo.getRoomName() + "租金及押金", 3)
                        .addCell("收款信息").addCell(String.format("%s、%s、%s、%s", vo.getPayeeName(), vo.getPayeeBankCode(), vo.getPayeeBankBranch(), vo.getPayeeBankAccount()), 3)
                        .addCell("房东名称", vo.getOwnerName(), "房东电话", vo.getOwnerPhone())
                        .addCell("申请支出金额", cell -> {
                            cell.setRowspan(2);
                            cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                        })
                        .addCell("小写").addCell(String.format("￥%.2f", vo.getPayAmount()), 2)
                        .addCell("大写").addCell(Convert.digitToChinese(vo.getPayAmount().doubleValue()), 2)
                        .addCell("附件").addCell("委托收房审核表编号：", 3);
                        // 账单信息
                        tb.addCell("订单明细", 4, bold, Element.ALIGN_LEFT)
                                .addCell("费用名称", "费用金额", "费用备注", "创建时间");
                        if (CollectionUtils.isNotEmpty(detail)) {
                            for (OrderFeesDO d : detail) {
                                tb.addCell(d.getFeeName(), String.format("￥%.2f", d.getAmount().subtract(d.getDiscountAmount())), "",
                                        DateUtil.format(d.getCreateTime(), "yyyy/MM/dd HH:mm:ss"));
                            }
                        }
                        tb.addCell("总计").addCell(String.format("￥%.2f", vo.getPayAmount()), 3);
                        // 流程处理信息
                        tb.addCell("处理信息记录", 4, bold, Element.ALIGN_LEFT);
                        if (StringUtils.isNotBlank(vo.getProcessInstanceId())) {
                            List<BpmTaskRespDTO> tasklist = bpmProcessInstanceApi.getAllTaskListByProcessInstanceId(vo.getProcessInstanceId());
                            PdfUtils.Table nestedTable = new PdfUtils.Table(5).addCell("处理人", "处理步骤", "审核意见", "处理结果", "处理时间");
                            if (CollectionUtils.isNotEmpty(tasklist)) {
                                for (BpmTaskRespDTO bpmTaskRespDTO : tasklist) {
                                    String handler = bpmTaskRespDTO.getAssigneeUsers().stream().findFirst().map(BpmTaskRespDTO.User::getNickname).orElse("");
                                    nestedTable.addCell(handler, bpmTaskRespDTO.getName(), bpmTaskRespDTO.getReason(), BpmProcessInstanceResultEnum.getResult(bpmTaskRespDTO.getResult()),
                                            bpmTaskRespDTO.getEndTime() != null ? DateUtil.format(bpmTaskRespDTO.getEndTime(), "yyyy/MM/dd HH:mm:ss") : "");
                                }
                            }
                            nestedTable.options(t -> {
                                t.setWidthPercentage(100);
                                try {
                                    t.setWidths(new float[]{18f, 32f, 18f, 12f, 20f});
                                } catch (DocumentException ignore) {
                                }
                            });
                            tb.addCell(nestedTable);
                        }
                        tb.options(t -> {
                            t.setWidthPercentage(100);
                            try {
                                t.setWidths(new float[]{18f, 32f, 18f, 32f});
                            } catch (DocumentException ignore) {
                            }
                        });
                    }
            );
            doc.getDoc().newPage();
        }
        doc.close();
        os.close();
    }

}
